﻿//#region 关于本系列:
//网上查找整理, 总结生成
//Reference: http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html
//#endregion>

//#region 1:关于全局变量
//要点1: 链式声明会自动定义全局变量
var a = b = 0; //b是全局变量

//要点2: 隐式全局变量并不是真正的全局变量，但它们是全局对象的属性。属性是可以通过delete操作符删除的，而变量是不能的

//要点3: 有时候window不是全局变量, 怎么得到呢?
var global = (function () {
    return this;
} ());

//#endregion

//#region 2:单var声明法
//在函数的顶部预先声明好变量,提供许多好处, 如:
//* 提供了一个单一的地方去寻找功能所需要的所有局部变量
//* 防止变量在定义之前使用的逻辑错误
//* 更重要的原因在下一点
var a,
    b,
    c = 0;
//#endregion

//#region 3:var的悬置(hoisting)
//在函数内部声明的var变量会被自动'提'到函数顶端, 如:
myname = "hello";
function say() {
    alert(myname);
    var myname = "jason";
    alert(myname);
}

say();
//输出:undefined
//输出:jason
//原因就是因为var虽然在后面定义, 但是他却被置顶了, 为了避免这种误判, 最好像上小节中那样在函数顶部预先声明变量;
//#endregion

//#region 4:for循环中的问题
//for在进行循环过程中有部分语句(判断,自增)是每次都会执行的,所以
//错误代码:
for (var i = 0; i < myarray.length; i++) {
    // 使用myarray[i]做点什么
}

//这种形式的循环的不足在于每次循环的时候数组的长度都要去获取下。这回降低你的代码，尤其当myarray不是数组，而是一个HTMLCollection对象的时候。HTMLCollections指的是DOM方法返回的对象,如:
document.getElementsByName('');
document.getElementsByClassName('');
document.getElementsByTagName('');

//正确的做法:
for (var i = 0, max = myarray.length; i < max; i++) {
    // 使用myarray[i]做点什么
}
//#endregion

//#region 5:不推荐扩展内置原型
//* 增加内置的构造函数原型（如Object(), Array(), 或Function()）挺诱人的，但是这严重降低了可维护性，因为它让你的代码变得难以预测。
//使用你代码的其他开发人员很可能更期望使用内置的 JavaScript方法来持续不断地工作，而不是你另加的方法。
//* 另外，属性添加到原型中，可能会导致不使用hasOwnProperty属性时在循环中显示出来，这会造成混乱。

//但是如果你满足某些规则则可以使用:
//* 可以预期将来的ECMAScript版本或是JavaScript实现将一直将此功能当作内置方法来实现。例如，你可以添加ECMAScript 5中描述的方法，一直到各个浏览器都迎头赶上。这种情况下，你只是提前定义了有用的方法。
//* 如果您检查您的自定义属性或方法已不存在——也许已经在代码的其他地方实现或已经是你支持的浏览器JavaScript引擎部分。
//* 你清楚地文档记录并和团队交流了变化
//形式如下:
if (typeof Object.prototype.mythod !== 'function') {
    Object.prototype.mythod = function () { 
        //do something
    }
}

//#endregion

//#region 6:区分'==' 和 '==='
//使用2者注意区分, 能使用'==='时不使用'==', 这样可以提高代码可读性
//避免了隐式转换
//#endregion

//#region 7:避免使用eval
//会引起代码篡改的问题,替代的方法:
obj[method] //替代eval('obj.'+method);

//#endregion

//#region 8:函数声明不受代码块约束
var f = function g() {
    return 1;
};
if (false) {
    f = function g() {
        return 2;
    };
}
g(); // 2
//首先防范标识符泄漏带外部作用域
//其次，应该永远不引用被用作函数名称的标识符
//#endregion

//#region 9:函数表达式的自执行
// var f = function(){}, 在这句话后面加个"()", 它就会自执行, 需要注意的是, 如果在 : function(){} 这句后面添加会提示错误,
// 因为只有函数表达式才可以自执行, 函数声明后面如果跟了一个"()", 这个"()"会被翻译成分组操作符(括号其中一个作用)
// 下面这个function在语法上是没问题的，但是依然只是一个语句
// 加上括号()以后依然会报错，因为分组操作符需要包含表达式
// 但是再加一个大括弧就可以了: (function(){})(); 这样或者 (function(){}()); 这样, 后者比较推荐, 这是因为括弧里不能包含语句(声明?), 所以加了括弧
// 会被自动当成表达式进行解析, 所以可以编译过了

//关于分组操作符: '()', 这个分组操作符就是相当于表达式中的一个优先运算, 例如: var a = (x = 1);会被js引擎解析为:
//1 先执行(x=1)此时x是一个global的变量
//2 再声明var a
//3 再将x=1的返回值赋值给a
//讲到的fuction自执行体系;
//#endregion

//#region 10:自执行和Module模式拓展
//在进行Module操作的时候往往会进行如下定义: 

var mymodule = function (eq) {
    var eqCtl = document.getElementById(eq);
    return {
        // 暴露公开的成员
        add: function (x, y) {
            var val = x + y;
            eqCtl.innerHTML = val;
        }
    }
}
//这样做会很无效, 如果要在多个文件中, 多个人一起扩展同一个模块, 同时, 加载时又不需要考虑优先顺序, 怎么做呢?:
//在A.js中可以这样定义
//var blogModule = (function (my) {
//    my.addPhoto = function () {
//        console.log('myphoto');
//    };
//    return my;
//} (blogModule || {}));

////在B.js中这样定义:
//var blogModule = (function (my) {
//    my.addFont = function () {
//        console.log('addFont');
//    };
//    return my;
//} (blogModule || {}));
//使用: blogModule.addFont(); 或 blogModule.addPhoto()
//这样, 这个对象就都添加上了扩展方法, 很赞吧? 原理如下(我理解的):
//同上面讲到的9中自定义函数的执行, 先定义出全局变量blogModule, 然后对其进行对象化装箱,然后通过匿名函数调用使这个对象变的丰满, 最后把对象返回给
//变量blogModule
//问: 其中的解析过程不是很清楚, 是先执行var blogModule 还是先执行 blogModule || {}, 我觉得是后者, 因为()中间是一个表达式
//#endregion


//#region 11:

//#endregion